<?php

namespace Plugins\IMApi;


use App\Util\ApiAuth;
use App\Util\Helper;
use Hyperf\Contract\ContainerInterface;
use Hyperf\Contract\OnCloseInterface;
use Hyperf\Contract\OnMessageInterface;
use Hyperf\Contract\OnOpenInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Server\ServerFactory;
use Hyperf\Server\ServerInterface;
use Hyperf\WebSocketServer\Context;
use Plugins\IMApi\Service\BindService;
use Plugins\IMApi\Service\MessageService;
use Plugins\IMApi\Service\SenderService;
use Psr\SimpleCache\InvalidArgumentException;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;

class WebSocketController implements OnMessageInterface, OnOpenInterface, OnCloseInterface
{
    private BindService $bindService;

    private WebSocketMessageHandlerInterface $messageService;

    private SenderService $senderService;

    public function __construct(ContainerInterface $container)
    {
        $server = $container->get(ServerFactory::class)->getServer()->getServer();
        $this->bindService = $container->get(BindService::class);
        $this->messageService = $container->get(WebSocketMessageHandlerInterface::class);
        $this->senderService = new SenderService($server, $this->bindService);
    }

    /**
     * @param Response|Server $server
     * @throws InvalidArgumentException
     */
    public function onClose($server, int $fd, int $reactorId): void
    {
        $this->bindService->unBindUserFd($fd);
    }

    /**
     * @param Response|Server $server
     * @param Frame $frame
     */
    public function onMessage($server, $frame): void
    {
        if ($frame->opcode === SWOOLE_WEBSOCKET_OPCODE_PING || strtolower($frame->data) === 'ping'){
            $responseFrame = new Frame();
            $responseFrame->opcode = SWOOLE_WEBSOCKET_OPCODE_PONG;
            $server->push($frame->fd, $responseFrame);
            return;
        }

          $this->messageService->onMessage($server, $frame, $this->senderService, $this->bindService);
    }

    /**
     * @param Response|Server $server
     * @param Request $request
     * @throws InvalidArgumentException
     */
    public function onOpen($server, $request): void
    {
        $responseFrame = new Frame();
        if (!ApiAuth::get('user_id')){
            $responseFrame->data = "open fail: " . $request->fd;
            $server->push($request->fd, $responseFrame);
            $server->close($request->fd);
            return;
        }
        $responseFrame->data = "open success: " . $request->fd;
        $server->push($request->fd, $responseFrame);
        $this->bindService->bindUserFd(ApiAuth::get('user_id', 0), $request->fd);
    }
}